package se.rivta.service.catalogue.ws;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import javax.jws.WebService;
import lombok.extern.slf4j.Slf4j;
import org.apache.camel.ExchangePattern;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.cdi.CdiCamelContext;
import org.apache.cxf.annotations.SchemaValidation;
import riv.service.catalogue._2.CVType;
import riv.service.catalogue._2.OfferType;
import riv.service.catalogue._2.ProductType;
import riv.service.catalogue._2.ResultType;
import riv.service.catalogue._2.SupportedInteractionsType;
import riv.service.catalogue.aggregated.enums._2.ErrorCodeEnum;
import riv.service.catalogue.aggregated.enums._2.ResultCodeEnum;
import se.riv.service.catalogue.findoffers.v2.rivtabp21.FindOffersResponderInterface;
import se.riv.service.catalogue.findoffersresponder.v2.FindOffersResponseType;
import se.riv.service.catalogue.findoffersresponder.v2.FindOffersType;
import se.sll.service.catalogue.common.helper.ExtractionHelper;
// REST-API datamodel
//import se.sll.service.catalogue.composite.data.CodeData;
// Common composite classes
import se.sll.service.catalogue.rivta.composite.exception.InvalidRequestException;
import se.sll.service.catalogue.composite.camel.cdi.CamelRoute;
import se.sll.service.catalogue.common.rest.response.HsaData;
import se.sll.service.catalogue.composite.camel.helper.RouteName;
import se.sll.service.catalogue.composite.helper.service.HsaCache;
import se.sll.service.catalogue.product.api.model.CodeResponse;

/**
 *
 * @author khaleddaham
 */
@Slf4j
@WebService(
        endpointInterface = "se.riv.service.catalogue.findoffers.v1.rivtabp21.FindOffersResponderInterface",
        serviceName = "FindOffers")
@SchemaValidation
public class FindOffers implements FindOffersResponderInterface {

    @Inject
    private CdiCamelContext camelCtx;
    @Inject
    private HsaCache hsaCache;

    private static final int MIN_WILDCARD_SEARCH = 3;

    @Override
    public FindOffersResponseType findOffers(String logicalAddress, FindOffersType request) {
        UUID logId = UUID.randomUUID();
        log.info("logId: {}, request: {}", logId.toString(), request.toString());
        FindOffersResponseType response = new FindOffersResponseType();
        response.setResult(new ResultType());
        try {
            if (request.getHSAId().isEmpty()) {
                log.debug("Filter search.");
                response = searchFilter(request);
            } else {
                log.debug("Quick search on hsaID.");
                response = searchByHsaId(request);
            }
        } catch (InvalidRequestException ire) {
            response.getResult().setResultCode(ResultCodeEnum.OK);
            response.getResult().setErrorCode(ErrorCodeEnum.INVALID_REQUEST);
            response.getResult().setLogId(logId.toString());
            response.getResult().setMessage(ire.getMessage());
            return response;
        } catch (Exception ex) {
            log.error("buildResponse failed", ex);
            response.getResult().setResultCode(ResultCodeEnum.OK);
            response.getResult().setErrorCode(ErrorCodeEnum.APPLICATION_ERROR);
            response.getResult().setLogId(logId.toString());
            response.getResult().setMessage(ex.getMessage());
            return response;
        }
        response.setResult(new ResultType());
        response.getResult().setResultCode(ResultCodeEnum.OK);
        response.getResult().setLogId(logId.toString());
        return enrichHsaData(response);
    }

    /**
     * Find all offers based on careUnitID
     *
     * @param findOffers
     * @return
     */
    private FindOffersResponseType searchByHsaId(FindOffersType findOffers) throws Exception {
        log.debug("searchByHsaId");
        ProducerTemplate template = camelCtx.createProducerTemplate();
        return (FindOffersResponseType) template.sendBody("direct:start:offers:byhsaid", ExchangePattern.InOut, findOffers.getHSAId());
    }

    /**
     * Find all offers based on filter criteria
     *
     * @param findOffers
     * @return
     */
    private FindOffersResponseType searchFilter(FindOffersType findOffers) throws Exception {
        log.debug("searchFilter: " + findOffers);
        FindOffersResponseType response = new FindOffersResponseType();
        ProducerTemplate template = camelCtx.createProducerTemplate();
        if (findOffers.getOrganizationName() != null) {
            if (findOffers.getOrganizationName().length() <= MIN_WILDCARD_SEARCH) {
                throw new InvalidRequestException("Wildcard search requires " + MIN_WILDCARD_SEARCH + " or more characters.");
            }
            List<String> hsaIdList = hsaCache.findHsaIdByRDN(findOffers.getOrganizationName());
            response = (FindOffersResponseType) template.sendBody("direct:start:offers:byhsaid", ExchangePattern.InOut, hsaIdList);
        } else if (findOffers.getProductCode().size() > 0) {
            for (CVType pct : findOffers.getProductCode()) {
                response = (FindOffersResponseType) template.sendBodyAndHeader(
                        CamelRoute.FROM_OFFER_BY_PRODUCT_CODE, ExchangePattern.InOut, null, "name", pct.getCode()
                );
            }
        }
        return filterResult(findOffers, response);
    }

    /**
     *
     * @param findOffers
     * @param response
     * @return
     */
    private FindOffersResponseType filterResult(FindOffersType findOffers, FindOffersResponseType response) {
        FindOffersResponseType filteredResponse = new FindOffersResponseType();
        log.debug("Filter product code: " + findOffers.getProductCode());
        log.debug("Filter supported interactions: " + findOffers.getInteraction());
        if (findOffers.getProductCode().isEmpty() && findOffers.getInteraction().isEmpty()) {
            return response;
        }

        // Filter on productCode
        if (findOffers.getProductCode() != null && findOffers.getProductCode().size() > 0) {
            for (OfferType o : response.getOffer()) {
                boolean keep = false;
                for (ProductType p : o.getProduct()) {
                    for (CVType match : findOffers.getProductCode()) {
                        if (p.getProperty().get(0).equals(match.getCode())) {
                            keep = true;
                            break;
                        }
                    }
                    if (keep) {
                        break;
                    }
                }
                if (keep) {
                    filteredResponse.getOffer().add(o);
                }
            }
        }

        // Filter on supportedInteractions
        if (findOffers.getInteraction().size() > 0) {
            return new FindOffersResponseType();
        }
        return filteredResponse;
    }

    /**
     *
     * @return
     */
    @SuppressWarnings("unchecked")
    private Collection<? extends CVType> getCodesForProduct(String productName) {
        List<CVType> ctList = new ArrayList<>();
        ProducerTemplate template = camelCtx.createProducerTemplate();
        List<CodeResponse> codeList = (List<CodeResponse>) template.sendBodyAndHeader(RouteName.CODE_RESPONSE_LIST_FOR_PRODUCT, ExchangePattern.InOut, null, "product", productName);
        for (CodeResponse cd : codeList) {
            CVType ct = new CVType();
            ct.setCode(cd.getCode());
            ct.setCodeSystem("1.2.752.129.2.2.1.3");
//            ct.setDescription(cd.getDescription());
            ct.setDisplayName(cd.getDisplayName());
            ctList.add(ct);
        }
        return ctList;
    }

    /**
     * @TODO duplicated code in all WS, move this to a processor.
     * @param response
     * @return
     */
    private FindOffersResponseType enrichHsaData(FindOffersResponseType response) {
        for (OfferType o : response.getOffer()) {
            if (o.getOrganizationalUnit().getHSAId().equals("SE5565189692-101J6")) {
                SupportedInteractionsType supportedInteraction = new SupportedInteractionsType();
                supportedInteraction.setInteraction("urn:riv:clinicalprocess:activity:request:ProcessRequest");
                supportedInteraction.setLogicalAddress("SE5565189692-101J6");
                o.getSupportedInteraction().add(supportedInteraction);
            }
            HsaData hsa = hsaCache.getHsa(o.getOrganizationalUnit().getHSAId());
            if (hsa == null) {
                continue;
            }
            try {
                o.getOrganizationalUnit().setOrganizationName(hsa.getRelativeDistinguishedName());
                o.getOrganizationalUnit().setPostalAddress(ExtractionHelper.getRivPostalAddressFromHsaPostalAddress(hsa.getPostalAddress()));
                o.getOrganizationalUnit().setPostalCode(ExtractionHelper.getRivPostalCodeFromHsaPostalAddress(hsa.getPostalAddress()));
                o.getOrganizationalUnit().setStreetAddress(hsa.getStreet());
                o.getOrganizationalUnit().setCountyCode(hsa.getCountyCode());
            } catch (Exception ex) {
            }
        }
        return response;
    }
}
